package com.magoldeditor.model;

import java.awt.Graphics;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;

import com.magoldeditor.at.MaEditorXMLException;
import com.magoldeditor.model.entity.Entity;
import com.magoldeditor.model.entity.IEntity;
import com.magoldeditor.model.entity.IEntityConstructor;
import com.magoldeditor.model.entity.IEntityDisplayer;
import com.magoldeditor.model.entity.IEntityFactory;
import com.magoldeditor.model.entity.MaEditorEntityConstructor;
import com.magoldeditor.model.entity.MaEditorEntityFactory;
import com.magoldeditor.util.xml.IContentReader;
import com.magoldeditor.util.xml.IXMLWriter;
import com.magoldeditor.view.IEditor;

/**
 * 
 * @author Velconia
 * @version v.2.0
 * 
 */
public class MaEditorMap extends Entity implements IMap, IMapData, IEditor {
	
	/**
	 * wheel up
	 */
	private static final int ENLARGE_UP = -1;
	private static final int ENLARGE_DOWN = 1;
	private static final double PER = 0.1d;
	
	/**
	 * move distance of camera
	 */
	private static final int MOVE_DISTACNE = 1;
	
	/**
	 * default screen of phone
	 */
	private static final int SCREEN_WIDTH = 800;
	private static final int SCREEN_HEIGHT = 480;
	
	/**
	 * list to store painter without the painter move with the mouse
	 */
	private LinkedList<IPainter> painterList = new LinkedList<IPainter>();
	
	/**
	 * show the choosed painter
	 */
	private IEditor painterEditor = null;
	
	/**
	 * help to paint
	 */
	private IEditor paintHelper = null;
	
	/**
	 * the painter move with mouse
	 */
	private IPainter mouseMover = null;
		
	/**
	 * a painter help to rotate the mouseMover
	 */
	private IPainter rotateHelper = null;
	
	/**
	 * camera
	 */
	private ICamera camera = null;
	
	/**
	 * entityfactory
	 */
	private IEntityFactory entityFactory = new MaEditorEntityFactory();
	
	/**
	 * a entity constructor help to construct the entity
	 */
	private IEntityDisplayer entityConstructor = null;
	
	/**
	 * 
	 * @param painterHelper
	 * @param height 
	 * @param width 
	 * @param y 
	 * @param x 
	 */
	public MaEditorMap(IEditor painterHelper, IEntityConstructor constructor, int x, int y, int width, int height, String name) {
		super(x, y, width, height, name);
		
		try {
			init(painterHelper, constructor);
		} catch (MaEditorXMLException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * init by map self
	 * @param displayPanel
	 */
	public MaEditorMap(String name, IEditor painterHelper, IEntityConstructor constructor) {
		super(name);
		
		try {
			init(painterHelper, constructor);
		} catch (MaEditorXMLException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 
	 * @param painter
	 * @throws MaEditorXMLException 
	 */
	private void init(IEditor painter, IEntityConstructor constructor) throws MaEditorXMLException {
		this.paintHelper = painter;
		this.entityConstructor = new MaEditorEntityConstructor(constructor);
		
		camera = new MaEditorCamera("Camera", this);
		
		ModelContants contants = ModelContants.getNewInstance();
		contants.initConfig(this);
	}
	
	@Override
	public void setWidth(int mapWidth) {
		if (mapWidth > SCREEN_WIDTH) this.width = mapWidth;
	}

	@Override
	public int getWidth() {
		return this.width;
	}

	@Override
	public void setHeight(int mapHeight) {
		if (mapHeight > SCREEN_HEIGHT) this.height = mapHeight;
	}

	@Override
	public int getHeight() {
		return this.height;
	}
/*
	@Override
	public void toCanvas(ICameraData camera) {
		if (this.camera != null && this.camera.isEnable()) {
			int tempX = this.camera.getX();
			int tempY = this.camera.getY();
			
			
			Iterator<IPainter> iterator = this.painterList.iterator();
			while (iterator.hasNext()) {
				IPainter p = iterator.next();
				p.setX(p.getX() - tempX);
				p.setY(p.getY() - tempY);
			}
			
		}
	}
*/
	@Override
	public void paintMethod(Graphics g) {
		Iterator<IPainter> iterator = this.painterList.iterator();
		
		while (iterator.hasNext()) {
			iterator.next().paintMethod(g, camera);
		}
		
		if (this.mouseMover != null && this.mouseMover.isEnable()) this.mouseMover.paintMethod(g);
		
		if (this.rotateHelper != null) this.rotateHelper.paintMethod(g);
	}

	@Override
	public void toDisk(IXMLWriter writer) {
		
	}

	@Override
	public String getName() {
		return "Map";
	}
	
	@Override
	public void fromDisk(IContentReader reader) {
		
	}

	@Override
	public void addPainter(IPainter painter) {
		if (painter != null) this.painterList.add(painter.clone());
	}

	@Override
	public void deletePainter(IPainter painter) {
		if (painter != null) this.painterList.remove(painter);
	}

	@Override
	public void setPainter(IPainter painter, int index) {
		if (painter != null) this.painterList.add(index, painter);
	}

	@Override
	public void setPainterList(IPainter[] painterList) {
		for (int i = 0; i < painterList.length; i++) {
			this.painterList.add(i, painterList[i]);
		}
	}

	@Override
	public IPainter getPainter(int index) {
		return this.painterList.get(index);
	}

	@Override
	public IPainter[] getPainterList(IPainter[] p) {
		if (p.length < this.painterList.size()) p = new IPainter[this.painterList.size()];
		return this.painterList.toArray(p);
	}
	
	@Override
	public void edit(IPainter[] painterList) {
		if (painterList != null) 
			for (int i = 0; i < painterList.length; i++) 
				this.painterList.add(painterList[i]);
		
		paintHelper.edit(null);
		//IPainter[] pl = new IPainter[this.painterList.size()];
		//System.err.println(this.painterEditor == null);
		//this.painterEditor.edit(this.painterList.toArray(pl));
	}

	@Override
	public void toRefresh() {
		
	}

	@Override
	public void toDisplay() {
		
	}

	@Override
	public void toChoose(String entityName) {
		IEntity e = entityFactory.createEntity(entityName);
		
		if (e != null && e.getID() != 0) {
			this.mouseMover = e;
			this.mouseMover.setEnable(true);
		} else {
			this.mouseMover = null;
			System.out.println("we did not have this entity!!");
		}
		
		this.edit(null);
	}

	@Override
	public IPainter toMove(int x, int y) {
		if (this.mouseMover != null && this.mouseMover.isEnable()) {
			this.mouseMover.setX(x + this.camera.getX());
			this.mouseMover.setY(y + this.camera.getY());
			this.rotateHelper = null;
			
			this.edit(null);
			return this.mouseMover;
		} else {
			return null;
		}
	}

	@Override
	public void toEntry(int x, int y) {
		if (this.mouseMover != null) {
			IPainter p = mouseMover.clone();
			p.setEnable(false);
			
			this.addPainter(p);
		} else {
			Iterator<IPainter> iterator = this.painterList.iterator();
			while (iterator.hasNext()) {
				IPainter painter = iterator.next();
				if (painter.isCrossed(x + camera.getX(), y + camera.getY())) {
					this.entityConstructor.display((IEntity) painter);
					System.err.println("crossed");
				} else {
					System.err.println("not crossed");
				}
			}
		}
		
		this.edit(null);
	}

	@Override
	public void toRotate(final int x1, final int y1) {
		if (this.mouseMover != null && this.mouseMover.isEnable()) {
			this.mouseMover.setAngle(toAngle(mouseMover.getX(), mouseMover.getY(), x1, y1));
			
			if (this.rotateHelper == null) 
				this.rotateHelper = new Entity(mouseMover.getX(), mouseMover.getY(), x1, y1, "RotateHelper") {
				
					@Override
					public void paintMethod(Graphics g) {
						g.drawLine(this.getX(), this.getY(), this.getWidth(), this.getHeight());
					}

					@Override
					public HashMap<String, String> getConstructor() {
						// TODO Auto-generated method stub
						return null;
					}

					@Override
					public void setConstructor(HashMap<String, String> map) {
						// TODO Auto-generated method stub
						
					}
				};
			else {
				this.rotateHelper.setWidth(x1);
				this.rotateHelper.setHeight(y1);
			}
			
			this.edit(null);
		}
	}
	
	private static final double toAngle(int x1, int y1, int x2, int y2) {
		if (Math.atan2(x1 - x2, y1 - y2) > 0) {
			return Math.PI - Math.atan2(x1 - x2, y1 - y2);
		} else {
			return Math.PI - Math.atan2(x1 - x2, y1 - y2);
		}
	}
	
	@Override
	public void toEnlarge(int wheelRotation) {
		if (this.mouseMover != null && this.mouseMover.isEnable()) {
			if (wheelRotation == ENLARGE_UP) this.mouseMover.setTimes(mouseMover.getTimes() + PER * ENLARGE_UP);
			if (wheelRotation == ENLARGE_DOWN) this.mouseMover.setTimes(mouseMover.getTimes() + PER * ENLARGE_DOWN);
			
			this.edit(null);
		}
	}
	
	public ICamera getCamera() {
		return camera;
	}

	public void setCamera(ICamera camera) {
		if (camera != null) this.camera = camera;
	}

	@Override
	public void toUp() {

		System.out.println("up");
		
		/*
		Iterator<IPainter> iterator = this.painterList.iterator();
		
		while (iterator.hasNext()) {
			IPainter p = iterator.next();
			p.setY(p.getY() + 1);
		}
		*/
		
		System.out.println("1camera y is" + camera.getY() + " this y is" + this.y);
		
		if (this.camera.getY() <= this.y) {
			this.height++;
			Iterator<IPainter> iterator = this.painterList.iterator();
			
			while (iterator.hasNext()) {
				IPainter p = iterator.next();
				p.setY(p.getY() + 1);
			}
			
			this.camera.setY(this.y);
			System.out.println("2camera y is" + camera.getY() + " this y is" + this.y);
		} else {
			this.camera.setY(this.camera.getY() - MOVE_DISTACNE);
			System.out.println("3camera y is" + camera.getY() + " this y is" + this.y);
		}
		
		this.edit(null);
	}

	@Override
	public void toLeft() {
		/*
		Iterator<IPainter> iterator = this.painterList.iterator();
		
		while (iterator.hasNext()) {
			IPainter p = iterator.next();
//			p.setX(p.getX() + 1);
		}
		*/
		
		if (this.camera.getX() <= this.x) {
			this.width++;
			Iterator<IPainter> iterator = this.painterList.iterator();
			
			while (iterator.hasNext()) {
				IPainter p = iterator.next();
				p.setX(p.getX() + 1);
			}
			
			this.camera.setX(this.x);
		} else this.camera.setX(this.camera.getX() - MOVE_DISTACNE);
		
		
		this.edit(null);
	}

	@Override
	public void toDown() {
		/*
		Iterator<IPainter> iterator = this.painterList.iterator();
		
		while (iterator.hasNext()) {
			IPainter p = iterator.next();
			p.setY(p.getY() - 1);
		}
		
		*/
		if (this.camera.getY() + this.camera.getHeight() >= this.height) this.height++;
		this.camera.setY(this.camera.getY() + MOVE_DISTACNE);
		
		this.edit(null);
	}

	@Override
	public void toRight() {
		/*
		Iterator<IPainter> iterator = this.painterList.iterator();
		
		while (iterator.hasNext()) {
			IPainter p = iterator.next();
			p.setX(p.getX() - 1);
		}
		*/
		
		if (this.camera.getX() + this.camera.getWidth() >= this.width) this.width++;
		this.camera.setX(this.camera.getX() + MOVE_DISTACNE);
		
		this.edit(null);
	}
	
	@Override
	public void setX(int x) {
		this.x = x;
	}
	
	@Override
	public void setY(int y) {
		this.y = y;
	}

	@Override
	public void focusOn() {
		this.paintHelper.focusOn();
	}

	@Override
	public HashMap<String, String> getConstructor() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public void setConstructor(HashMap<String, String> map) {
		// TODO Auto-generated method stub
		
	}
}